package online.flowerinsnow.minecraft.bukkit.manhunt.listener;

import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import online.flowerinsnow.minecraft.bukkit.manhunt.core.hunter.OnDead;
import org.bukkit.*;
import org.bukkit.boss.BarColor;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import online.flowerinsnow.minecraft.bukkit.manhunt.Manhunt;
import online.flowerinsnow.minecraft.bukkit.manhunt.config.ManhuntConfiguration;
import online.flowerinsnow.minecraft.bukkit.manhunt.core.PlayerTeam;
import online.flowerinsnow.minecraft.bukkit.manhunt.event.PlayerAttackEvent;
import online.flowerinsnow.minecraft.bukkit.manhunt.event.PlayerDiedEvent;
import online.flowerinsnow.minecraft.bukkit.manhunt.manager.IBossBarManager;
import online.flowerinsnow.minecraft.bukkit.manhunt.manager.ITeamManager;
import online.flowerinsnow.minecraft.bukkit.manhunt.util.CompassUtils;
import online.flowerinsnow.minecraft.bukkit.manhunt.util.MessageUtils;
import online.flowerinsnow.minecraft.bukkit.manhunt.util.StateUtils;
import online.flowerinsnow.minecraft.bukkit.manhunt.util.VersionUtils;

import java.util.*;

public class PlayerListener implements Listener {
    private final Map<Player, Long> specTpCd = new HashMap<>();
    private final Map<Player, BukkitTask> healthBarInvisible = new HashMap<>();

    @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
    public void onPlayerDeath(PlayerDiedEvent e) {
        publishDeathMessage(e.cause, e.player, e.killer);
        Manhunt.runTask(() -> {
            e.player.getWorld().strikeLightningEffect(e.player.getLocation());
            ITeamManager teamManager = Manhunt.getTeamManager();
            PlayerTeam team = teamManager.getPlayerTeam(e.player);
            if (team == PlayerTeam.HUNTER || team == PlayerTeam.RUNNER) e.player.getWorld().dropItem(e.player.getLocation(), VersionUtils.getSkullOf(e.player));

            //noinspection ConstantConditions
            if (!e.player.getWorld().getGameRuleValue(GameRule.KEEP_INVENTORY)) {
                dropInventory(e.player);
                StateUtils.clearInventory(e.player);
            }

            if (team == PlayerTeam.HUNTER) {
                if (ManhuntConfiguration.Hunter.ondead == OnDead.BECOME_SPECTATOR) {
                    teamManager.setPlayerTeam(e.player, PlayerTeam.SPECTATOR);
                    return;
                }
                if (ManhuntConfiguration.Hunter.ondead == OnDead.RESPAWN) {
                    e.player.getInventory().addItem(new ItemStack(Material.COMPASS));
                    if (e.player.getBedSpawnLocation() == null) {
                        //noinspection ConstantConditions
                        e.player.teleport(Bukkit.getWorld("arena").getSpawnLocation());
                    } else {
                        e.player.teleport(e.player.getBedSpawnLocation());
                    }
                    return;
                }
                return;
            }
            if (team == PlayerTeam.RUNNER) {
                if (ManhuntConfiguration.Runner.ondead == online.flowerinsnow.minecraft.bukkit.manhunt.core.runner.OnDead.BECOME_SPECTATOR) {
                    teamManager.setPlayerTeam(e.player, PlayerTeam.SPECTATOR);
                    return;
                }
                if (ManhuntConfiguration.Runner.ondead == online.flowerinsnow.minecraft.bukkit.manhunt.core.runner.OnDead.BECOME_HUNTER) {
                    teamManager.setPlayerTeam(e.player, PlayerTeam.HUNTER);
                    //noinspection ConstantConditions
                    e.player.teleport(Bukkit.getWorld("arena").getSpawnLocation());
                    return;
                }
                //noinspection UnnecessaryReturnStatement
                return;
            }
        });
    }
    @EventHandler
    public void onInteractCompass(PlayerInteractEvent e) {
        ITeamManager teamManager = Manhunt.getTeamManager();
        PlayerTeam team = teamManager.getPlayerTeam(e.getPlayer());
        if (team != PlayerTeam.SPECTATOR || !(e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)) return;
        //noinspection ConstantConditions
        if (e.getPlayer().getInventory().getItem(0) == null || e.getPlayer().getInventory().getItem(0).getType() != Material.COMPASS) {
            e.getPlayer().getInventory().setItem(0, CompassUtils.val_9_a);
        }
        if (e.getItem() != null && e.getItem().getType() == Material.COMPASS) {
            long l = specTpCd.getOrDefault(e.getPlayer(), -1L);
            if (l > System.currentTimeMillis()) {
                e.getPlayer().sendMessage(MessageUtils.parseColor("&7[&c×&7]&c请等待3秒再执行此操作"));
                e.getPlayer().playSound(e.getPlayer().getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 1);
                return;
            }
            List<Player> playerList = new ArrayList<>();
            playerList.addAll(teamManager.getHunters());
            playerList.addAll(teamManager.getRunners());
            if (playerList.size() == 0) {
                e.getPlayer().sendMessage(MessageUtils.parseColor("&7[&c×&7]&c没有可以传送的玩家"));
                e.getPlayer().playSound(e.getPlayer().getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 1);
                return;
            }
            Player target = playerList.get(new Random().nextInt(playerList.size()));
            e.getPlayer().teleport(target);
            e.getPlayer().playSound(e.getPlayer().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
            e.getPlayer().sendMessage(MessageUtils.parseColor("&7[&b!&7]&b您传送到了 &e" + target.getName()));
            specTpCd.put(e.getPlayer(), System.currentTimeMillis() + 3000L);
        }
    }
    /*
    @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
    public void onDamager(EntityDamageByEntityEvent e) {
        if (!(e.getEntity() instanceof Damageable)) return;
        Damageable entity = (Damageable) e.getEntity();
        Entity damager = e.getDamager();
        if (damager instanceof Projectile) {
            Projectile projectile = (Projectile) damager;
            if (!(projectile.getShooter() instanceof Player)) return;
            damager = (Entity) projectile.getShooter();
        }
        if (damager instanceof Player) {
            Player player = (Player) damager;
            IBossBarManager bossBarManager = Manhunt.getBossBarManager();
            double progress;
            //noinspection deprecation
            double maxhealth = entity.getMaxHealth();
            double health = 0;
            if (entity instanceof Player) {
                health = entity.getAbsorptionAmount();
            }
            health += entity.getHealth();
            health -= e.getFinalDamage();
            if (health < 0) health = 0;
            progress = health / maxhealth;
            if (progress > 1) progress = 1;

            BarColor barColor;
            ChatColor chatColor;
            if (progress > 0.6) {
                barColor = BarColor.GREEN;
                chatColor = ChatColor.YELLOW;
            } else if (progress > 0.3) {
                barColor = BarColor.YELLOW;
                chatColor = ChatColor.GOLD;
            } else {
                barColor = BarColor.RED;
                chatColor = ChatColor.RED;
            }

            final String val_5_l = "§b伤害: §e" + String.format("%.2f", e.getFinalDamage()) + " §b剩余生命值: " +
                    chatColor + String.format("%.2f", health) + "§b/§a" + String.format("%.2f", maxhealth) + "§c❤";
            bossBarManager.setPlayerBossBarColor(player, barColor);
            bossBarManager.setPlayerBossBarTitle(player, val_5_l);
            bossBarManager.setPlayerBossBarProgress(player, progress);
            showBossBarAndHideOn3s(player);
        }
    }
     */
    @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
    public void onAttack(PlayerAttackEvent e) {
        if (!(e.entity instanceof Damageable)) return;
        Damageable entity = (Damageable) e.entity;
        IBossBarManager bossBarManager = Manhunt.getBossBarManager();
        double progress;
        //noinspection deprecation
        double maxhealth = entity.getMaxHealth();
        double health = 0;
        if (entity instanceof Player) {
            health = entity.getAbsorptionAmount();
        }
        health += entity.getHealth();
        health -= e.showedDamage;
        if (health < 0) health = 0;
        progress = health / maxhealth;
        if (progress > 1) progress = 1;

        BarColor barColor;
        ChatColor chatColor;
        if (progress > 0.6) {
            barColor = BarColor.GREEN;
            chatColor = ChatColor.YELLOW;
        } else if (progress > 0.3) {
            barColor = BarColor.YELLOW;
            chatColor = ChatColor.GOLD;
        } else {
            barColor = BarColor.RED;
            chatColor = ChatColor.RED;
        }

        final String val1 = "§b伤害: §e" + String.format("%.2f", e.showedDamage) + " §e" + getEntityName(entity) + " §b剩余生命值: " +
                chatColor + String.format("%.2f", health) + "§b/§a" + String.format("%.2f", maxhealth) + "§c❤";
        bossBarManager.setPlayerBossBarColor(e.player, barColor);
        bossBarManager.setPlayerBossBarTitle(e.player, val1);
        bossBarManager.setPlayerBossBarProgress(e.player, progress);
        showBossBarAndHideOn3s(e.player);

        if (e.entity instanceof Player) {
            Player target = (Player) e.entity;
            PlayerTeam team1 = Manhunt.getTeamManager().getPlayerTeam(target);
            PlayerTeam team2 = Manhunt.getTeamManager().getPlayerTeam(e.player);
            if (team1 != null && team1 == team2) {
                e.player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(MessageUtils.parseColor("&c注意：不要伤害你的队友")));
            }
        }
    }
    @EventHandler
    public void onDropCompass(PlayerDropItemEvent e) {
        if (e.getItemDrop().getItemStack().getType() == Material.COMPASS) e.setCancelled(true);
    }
    @SuppressWarnings("ConstantConditions")
    @EventHandler
    public void onNetherPortal(PlayerPortalEvent e) {
        if ("arena".equals(e.getFrom().getWorld().getName())) {
            e.getTo().setWorld(Bukkit.getWorld("nether"));
            return;
        }
        if ("nether".equals(e.getFrom().getWorld().getName())) {
            e.getTo().setWorld(Bukkit.getWorld("arena"));
            return;
        }
        e.setCancelled(true);
    }
    @SuppressWarnings("ConstantConditions")
    @EventHandler
    public void onEndPortal(PlayerTeleportEvent e) {
        if (e.getCause() != PlayerTeleportEvent.TeleportCause.END_PORTAL) return;
        if ("arena".equals(e.getFrom().getWorld().getName())) {
            e.setTo(Bukkit.getWorld("theend").getSpawnLocation());
        }
    }

    private void showBossBarAndHideOn3s(Player player) {
        IBossBarManager bossBarManager = Manhunt.getBossBarManager();
        bossBarManager.setPlayerBossBarVisible(player, true);
        BukkitTask task = healthBarInvisible.get(player);
        if (task != null) task.cancel();
        task = new BukkitRunnable() {
            @Override
            public void run() {
                healthBarInvisible.remove(player);
                bossBarManager.setPlayerBossBarVisible(player, false);
            }
        }.runTaskLater(Manhunt.getInstance(), 60L);
        healthBarInvisible.put(player, task);
    }

    private String getPlayerName(Player player) {
        String playerName = player.getName();
        PlayerTeam team = Manhunt.getTeamManager().getPlayerTeam(player);
        if (team != null) {
            playerName = switch (team) {
                case HUNTER -> "§c[猎人]" + playerName;
                case RUNNER -> "§b[逃跑者]" + playerName;
                case SPECTATOR -> "§7[旁观者]" + playerName;
            };
        }
        return playerName;
    }
    private String getEntityName(Entity entity) {
        if (entity == null) return "个寂寞";
        if (entity instanceof Player) return getPlayerName((Player) entity);
        return entity.getCustomName() == null ? entity.getName() : entity.getCustomName();
    }
    private String getKilledMessage(Entity killer) {
        String killedMessage = " ";
        if (killer != null) {
            killedMessage = " §b在与 §c" + getEntityName(killer) + " §b交战时";
        }
        return killedMessage;
    }
    private void dropInventory(Player player) {
        World world = player.getWorld();
        Location location = player.getLocation();
        PlayerInventory inv = player.getInventory();
        for (int i = 0; i < 41; i++) {
            ItemStack item = inv.getItem(i);
            if (item == null || item.getType() == Material.COMPASS) continue;
            world.dropItem(location, item);
        }
        int dropExp = Math.min(player.getLevel() * 7, 100);
        if (dropExp > 0) {
            ExperienceOrb orb = (ExperienceOrb) world.spawnEntity(location, EntityType.EXPERIENCE_ORB);
            orb.setExperience(dropExp);
        }
    }

    private void publishDeathMessage(EntityDamageEvent.DamageCause cause, Player player, Entity killer) {
        String deathMessage;
        String playerName = getPlayerName(player);
        String killedMessage = getKilledMessage(killer);
        deathMessage = switch (cause) {
            case FALL -> playerName + killedMessage + "§b摔成了碎屑";
            case FIRE -> playerName + killedMessage + "§b被烤糊了";
            case LAVA -> playerName + killedMessage + "§b试图在岩浆里游泳";
            case VOID -> playerName + killedMessage + "§b掉入了虚空";
            case MAGIC -> playerName + killedMessage + "§b被法术伤害杀死";
            case DRYOUT -> playerName + killedMessage + "§b在水里 但没完全在水里 干死了";
            case POISON -> playerName + killedMessage + "§b中毒身亡 等等...中毒能死人?出bug了吧?";
            case THORNS -> playerName + killedMessage + "§b被反甲杀死了";
            case WITHER -> playerName + killedMessage + "§b凋谢了";
            case CONTACT -> playerName + killedMessage + "§b被扎死了";
            case MELTING -> playerName + killedMessage + "§b融化了 等等...不是只有雪傀儡能受到这种伤害的吗?";
            case SUICIDE -> playerName + killedMessage + "§b被 §c" + playerName + "§b杀死了\n" +
                    "§b这个世界虽然不完美 我们仍可以治愈自己\n" +
                    "§b北京24小时免费心理危机咨询热线: §e010-8295-1332";
            case CRAMMING -> playerName + killedMessage + "§b因实体太多 被挤死了";
            case DROWNING -> playerName + killedMessage + "§b被水淹没 不知所措";
            case FIRE_TICK -> playerName + killedMessage + "§b被烤成八分熟";
            case HOT_FLOOR -> playerName + killedMessage + "§b发现这地板很烫脚";
            case LIGHTNING -> playerName + killedMessage + "§b遭到天谴 一道雷给劈成了全熟";
            case PROJECTILE -> playerName + " §b被 §c" + getEntityName(killer) + " §b射杀";
            case STARVATION -> playerName + killedMessage + "§b长时间饥饿导致死亡";
            case SUFFOCATION -> playerName + killedMessage + "§b被活埋或被边界吞噬";
            case DRAGON_BREATH -> playerName + killedMessage + "§b被龙吐了一口痰 吐死了";
            case ENTITY_ATTACK -> playerName + " §b被 §c" + getEntityName(killer) + " §b杀死了";
            case FALLING_BLOCK -> playerName + killedMessage + "§b被砸的头破血流";
            case FLY_INTO_WALL -> playerName + killedMessage + "§b因为装逼撞壁而死";
            case BLOCK_EXPLOSION, ENTITY_EXPLOSION -> playerName + killedMessage + "§b随着Boom一声化为灰烬";
            case ENTITY_SWEEP_ATTACK -> playerName + killedMessage + "§b被横扫溅伤扫死";
            case FREEZE -> playerName + killedMessage + "§b忘记穿衣服冻死了";
            default -> playerName + killedMessage + "§b死了 我也不知道咋死的";
        };
        Bukkit.broadcastMessage(deathMessage);
    }
}
